package org.kalai.unifypay.huanpay;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import org.apache.log4j.Logger;
import org.kalai.unifypay.util.CipherUtils;

public class HuanHelper {
	private static final Logger logger = Logger.getLogger(HuanHelper.class);
	
	private static Map<String, KeyPair> keyMap = new HashMap<>();
	
	public static final String SIGN_ALGORITHMS = "SHA1WithRSA";
	public static final String ENCODING = "UTF-8";
	
	static{
		String[] strArr = {"800330048161492", "800330048161493", "800330048161494", "800330048161506"};
		for (String str : strArr) {
			try {
				KeyFactory kf = KeyFactory.getInstance("RSA");
				PublicKey publicKey = (RSAPublicKey) kf.generatePublic(new X509EncodedKeySpec(CipherUtils.decryptBase64(readPem(str+"_pub"))));
				kf = KeyFactory.getInstance("RSA");
				PrivateKey privateKey = (RSAPrivateKey) kf.generatePrivate(new PKCS8EncodedKeySpec(buildPKCS8Key(readPem(str+"_prv"))));
				keyMap.put(str, new KeyPair(publicKey, privateKey));
			} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
				logger.error(e.getMessage(), e);
			}
		}
	}
	
	public static String sign(TreeMap<String, Object> params, String keyName){
		try {
			StringBuffer buf = new StringBuffer();
			for (Map.Entry<String, Object> param : params.entrySet()) {
				if(!"".equals(param.getValue())){
					buf.append(param.getKey()).append("=").append(param.getValue()).append("&");
				}
			}
			KeyPair keyPair = keyMap.get(keyName);
			if(keyPair == null){
				logger.error("密钥对不存在[" + keyName + "]");
				return null;
			}
			Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
			signature.initSign(keyPair.getPrivateKey());
			signature.update(buf.substring(0, buf.length() - 1).getBytes(ENCODING));
			return CipherUtils.encryptBase64(signature.sign());
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return null;
		}
	}
	
	public static boolean design(String ret, String keyName) {
		try {
			KeyPair keyPair = keyMap.get(keyName);
			if(keyPair == null){
				logger.error("密钥对不存在[" + keyName + "]");
				return false;
			}
			String data[] = ret.split("&");
	        StringBuffer buf = new StringBuffer();
	        String signature = "";
	        for (int i = 0; i < data.length; i++) {
	            String tmp[] = data[i].split("=", 2);
	            if ("signature".equals(tmp[0])) {
	                signature = tmp[1];
	            } else {
	                buf.append(tmp[0]).append("=").append(tmp[1]).append("&");
	            }
	        }
	        String signatureStr = buf.substring(0, buf.length() - 1);
			Signature sign = Signature.getInstance(SIGN_ALGORITHMS);
			sign.initVerify(keyPair.getPublicKey());
			sign.update(signatureStr.getBytes(ENCODING));
			return sign.verify(CipherUtils.decryptBase64(signature));
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return false;
		}
	}
	
	public static Map<String, String> getMap(String ret) {
        String data[] = ret.split("&");
        Map<String, String> map = new HashMap<>();
        for (int i = 0; i < data.length; i++) {
            String tmp[] = data[i].split("=", 2);
            map.put(tmp[0], tmp[1]);
        }
        return map;
    }
	
	private static String readPem(String path){
		BufferedReader br = null;
		try {
			br = new BufferedReader(new InputStreamReader(HuanHelper.class.getResourceAsStream("/huanpay/" + path + ".pem")));
			String s = br.readLine();
			String str = "";
			s = br.readLine();
			while (s.charAt(0) != '-') {
				str += s+"\r";
				s = br.readLine();
			}
			return str;
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return null;
		} finally {
			try {
				br.close();
			} catch (IOException e) {
				logger.error(e.getMessage(), e);
			}
		}
	}
	

	private static byte[] buildPKCS8Key(String privateKey){
        final byte[] innerKey = CipherUtils.decryptBase64(privateKey);
        final byte[] result = new byte[innerKey.length + 26];
        System.arraycopy(CipherUtils.decryptBase64("MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKY="), 0, result, 0, 26);
        System.arraycopy(BigInteger.valueOf(result.length - 4).toByteArray(), 0, result, 2, 2);
        System.arraycopy(BigInteger.valueOf(innerKey.length).toByteArray(), 0, result, 24, 2);
        System.arraycopy(innerKey, 0, result, 26, innerKey.length);
        return result;
    }
}
